<template>
  <view class="chat-container">
    <!-- 状态栏占位 -->
    <view class="nav-bar"></view>

    <!-- 顶部信息栏 -->
    <view class="header">
      <view class="user-info">
        <image class="avatar" :src="targetUser.avatar"/>
        <text class="nickname">{{ targetUser.nickname }}</text>
        <text class="status" :class="{ online: isServiceOnline }">
          {{ isServiceOnline ? '在线' : '离线' }}
        </text>
      </view>
    </view>

    <!-- 在线聊天界面 -->
    <template v-if="websocketReady">
      <scroll-view
          ref="messageList"
          class="message-list"
          scroll-y
          :scroll-top="scrollTop"
          @scrolltoupper="loadMoreMessages"
          refresher-enabled
          :refresher-triggered="isRefreshing"
          @refresherrefresh="onRefresh"
          :scroll-into-view="lastMessageId"
          :style="{ height: scrollViewHeight + 'px' }"
      >
        <view calss="message-list-box">
          <view class="loading" v-if="isLoading">加载中...</view>
          <view
              v-for="(msg, index) in messages"
              :key="index"
              :class="['message-item', msg.isSelf ? 'self' : 'other']"
          >
            <image class="avatar" :src="msg.avatar"/>
            <view class="message-content" :class="msg.type">
              <!-- 文本消息 -->
              <text v-if="msg.type === 'text'" class="text">{{ msg.content }}</text>

              <!-- 图片消息 -->
              <image
                  v-else-if="msg.type === 'image'"
                  :src="msg.content"
                  mode="widthFix"
                  @tap="previewImage(msg.content)"
                  class="msg-image"
              />

              <!-- 文件消息 -->
              <view v-else-if="msg.type === 'file'" class="file-message" @tap="downloadFile(msg)">
                <image v-if="msg.file_info" class="file-icon" :src="getFileIcon(msg.file_info.type)"/>
                <view v-if="msg.file_info" class="file-info">
                  <text class="file-name">{{ msg.file_info.name }}</text>
                  <text class="file-size">{{ msg.file_info.size }}</text>
                </view>
                <view class="download-icon">下载</view>
              </view>

              <!--商品卡-->
              <view v-else-if="msg.type === 'goods'" class="goods-message" @tap="goodsDetail(msg.goods_info.goods_id)">

                <view class="goods-info">
                  <image class="goods-image" :src="msg.goods_info.goods_image"/>
                  <view class="goods-name">{{ msg.goods_info.goods_name }}</view>
                </view>
                <view class="goods-price">￥{{ msg.goods_info.goods_price }}</view>
              </view>
              <!--订单-->
              <view v-else-if="msg.type === 'order'" class="order-message" @tap="orderDetail(msg.order_info.order_sn)">
                <view class="order-info">
                  <image class="order-image" :src="msg.order_info.goods_image"/>
                  <view class="order-name">单号：<text class="order-sn">{{ msg.order_info.order_sn }}</text></view>
                </view>
                <view class="order-price">应付款：￥{{ msg.order_info.order_pay_price }}</view>
                <view class="order-price">已付款：￥{{ msg.order_info.pay_price }}</view>
              </view>

              <view class="status" v-if="msg.isSelf && msg.status ==='sending' || msg.status==='failed'">
                <text v-if="msg.status === 'sending'">发送中...</text>
                <text v-else-if="msg.status === 'failed'">发送失败</text>
              </view>
            </view>
          </view>
        </view>

      </scroll-view>
      <!-- 底部输入区域 -->
      <view class="input-area">
        <view class="toolbar">
          <image class="tool-icon" src="https://source.alipay168.cn/skushop/48d320fb9838f39c6f144f58577d4b4a.png"
                 @tap="toggleEmojiPanel"/>
          <image class="tool-icon" src="https://source.alipay168.cn/skushop/6a64b3040d1bab1106f8c48923bfe087.png"
                 @tap="chooseImage"/>
          <image class="tool-icon" src="https://source.alipay168.cn/skushop/d833ceab73d75036b8538b2356c49ec1.png"
                 @tap="chooseFile"/>
        </view>
        <view class="input-box">
          <u-input
              v-model="inputMessage"
              class="input"
              type="textarea"
              :adjust-position="false"
              :cursor-spacing="0"
              :show-confirm-bar="false"
              :auto-height="true"
              placeholder="请输入消息"
          />
          <button class="send-btn" @tap="sendMessage">发送</button>
        </view>
        <!-- 表情面板 -->
        <view class="emoji-panel" v-if="showEmojiPanel">
          <view
              class="emoji-item"
              v-for="(emoji, index) in emojiList"
              :key="index"
              @tap="selectEmoji(emoji)"
          >
            {{ emoji }}
          </view>
        </view>
      </view>

    </template>

    <!-- 离线留言界面 -->
    <template v-else>
      <view class="leave-message">
        <view class="leave-message-title">客服暂时离线，请留言</view>
        <view class="form-item">
          <textarea v-model="leaveMessage.content" placeholder="请输入留言内容"/>
        </view>
        <button class="submit-btn" @tap="submitLeaveMessage">提交留言</button>
      </view>
    </template>

  </view>
</template>

<script>
import {chat_list, chat_ready, offline_msg} from "@/pages/packageA/kefu/chat_api";
import constConfig from "@/const";

export default {
  components: {},
  data() {
    return {
      targetUser: {
        id: '0',
        avatar: 'https://source.alipay168.cn/skushop/d971248a1565ebf807b6454e6f818916.png',
        nickname: '客服小王'
      },
      userInfo: {
        avatar: 'https://source.alipay168.cn/skushop/a14a2eb8bedcc7d07ee58a4440e9e460.png',
        nickname: '用户昵称'
      },
      messages: [],
      inputMessage: '',
      scrollTop: 0,
      showEmojiPanel: false,
      isLoading: false,
      isRefreshing: false,
      page: 1,
      pageSize: 20,
      historyMessages: [],
      fileIcons: {
        pdf: 'https://source.alipay168.cn/skushop/a4ac61fc8778b095bf913be7dcf0ac0c.png',
        doc: 'https://source.alipay168.cn/skushop/4ab03286576772c335155e55c2cdfc30.png',
        docx: 'https://source.alipay168.cn/skushop/4ab03286576772c335155e55c2cdfc30.png',
        xls: 'https://source.alipay168.cn/skushop/29462525a7589c1856d1d20d44c07289.png',
        xlsx: 'https://source.alipay168.cn/skushop/29462525a7589c1856d1d20d44c07289.png',
        png: 'https://source.alipay168.cn/skushop/073676a7387be6c78da3c90b48c720d4.png',
        jpg: 'https://source.alipay168.cn/skushop/073676a7387be6c78da3c90b48c720d4.png',
        jpeg: 'https://source.alipay168.cn/skushop/073676a7387be6c78da3c90b48c720d4.png',
        gif: 'https://source.alipay168.cn/skushop/073676a7387be6c78da3c90b48c720d4.png',
        ppt: 'https://source.alipay168.cn/skushop/df48fed9eab6fc6ff32a84a8452dea02.png',
        default: 'https://source.alipay168.cn/skushop/8522684198fdc137ed94fce7317b30cc.png'
      },
      emojiList: ['😀', '😂', '🤣', '😊', '😇', '🙂', '🙃', '😉', '😌', '😍', '🥰', '😘', '😋', '😛', '😝', '😜', '🤪', '🤨', '🧐', '🤓'],
      isServiceOnline: true, // 客服在线状态
      websocketReady: false,
      websocket: null, // websocket 实例
      reconnectTimes: 0, // 重连次数
      socketUrl: 'wss://example.com/chat',
      maxReconnectTimes: 3, // 最大重连次数
      heartbeatInterval: null, // 新增心跳检测定时器
      leave: false,
      lastMessageId: '',
      leaveMessage: {
        name: '',
        phone: '',
        content: ''
      },
      scrollViewHeight: 0, // 用于设置 scroll-view 的高度
      options: null,

      uploadImageUrl: constConfig.baseUrl + '/upload/image',
      uploadFileUrl: constConfig.baseUrl + '/upload/file',
      maxSize: 2 * 1024 * 1024, // 可以设置不同的大小限制
      maxCount: 3, // 可以设置不同的数量限制
      limitType: ['png', 'jpg', 'jpeg'], // 支持的文件类型
    }
  },
  onLoad(options) {
    this.options = options
    // 获取状态栏高度
    const systemInfo = uni.getSystemInfoSync()
    this.statusBarHeight = systemInfo.statusBarHeight
    console.log('statusBarHeight', systemInfo.statusBarHeight)
    if (options.kefu_id) {
      this.targetUser.id = options.kefu_id
    }
    // 检查客服在线状态
    this.get_chat_ready(options)
  },
  mounted() {
    this.calculateScrollViewHeight();
    this.loadMoreMessages(); // 加载历史消息
  },
  beforeDestroy() {
    console.log('页面销毁')
    this.leave = true
    this.closeWebSocket();
  },
  onUnload() {
    console.log('页面卸载')
    this.leave = true
    this.closeWebSocket();
  },
  methods: {
    goodsDetail(goods_id) {
      uni.navigateTo({
        url: '/pages/goods/detail?item_id=' + goods_id
      })
    },
    orderDetail(order_sn) {
      uni.navigateTo({
        url: '/pages/packageA/order/detail?order_sn=' + order_sn
      });
    },
    closeWebSocket() {
      if (this.websocket) {
        this.websocket.close();
        this.websocket = null;
      }
      if (this.heartbeatInterval) { // 清除心跳检测定时器
        clearInterval(this.heartbeatInterval);
        this.heartbeatInterval = null;
      }
    },
    // 检查客服在线状态
    async get_chat_ready(options) {

      try {
        const res = await chat_ready(options)
        if (res.code !== 0) {
          uni.showToast({
            title: res.msg,
            icon: 'none'
          })
          return;
        }
        this.isServiceOnline = res.data.online
        this.targetUser = res.data.targetUser
        this.socketUrl = res.data.socketUrl
        this.maxReconnectTimes = res.data.maxReconnectTimes
        this.connectWebSocket()
        await this.loadMoreMessages()

        if (res.data.goodsInfo) {
          let that = this
          setTimeout(() => {
            that.send({
              type: 'goods',
              isSelf: true,
              avatar: this.userInfo.avatar,
              goods_info: res.data.goodsInfo
            })
          }, 1000)
        } else if (res.data.orderInfo) {
          let that = this
          setTimeout(() => {
            that.send({
              type: 'order',
              isSelf: true,
              avatar: this.userInfo.avatar,
              order_info: res.data.orderInfo
            })
          }, 1000)
        }


      } catch (error) {
        uni.showToast({
          title: error,
          icon: 'none'
        })
        console.error('检查客服状态失败:', error)
        this.isServiceOnline = false
      }
    },

    // 连接 WebSocket
    connectWebSocket() {
      this.websocket = uni.connectSocket({
        url: this.socketUrl,
        success: () => {
          console.log('WebSocket连接成功')
          this.websocketReady = true
        },
        fail: (err) => {
          console.error('WebSocket连接失败', err)
        }
      })

      this.websocket.onOpen(() => {
        console.log('WebSocket连接已打开')
        this.reconnectTimes = 0
        let token = (uni.getStorageSync('UserToken') || '');
        if (token) {
          this.websocket.send({
            data: JSON.stringify({
              type: 'login',
              targetUser: this.targetUser,
              token: token
            })
          })
        }
        // 设置心跳检测定时器
        this.heartbeatInterval = setInterval(() => {
          if (this.websocket) {
            this.websocket.send({
              data: JSON.stringify({
                type: 'ping',
                token: (uni.getStorageSync('UserToken') || '')
              }),
              success: () => {
                console.log('心跳检测成功')
              },
              fail: (err) => {
                console.log('心跳检测失败', err)
              }
            })
          }
        }, 30000)
      })

      this.websocket.onClose(() => {
        console.log('WebSocket连接已关闭')
        this.handleWebSocketClose()
      })

      this.websocket.onError(() => {
        console.log('WebSocket连接错误')
        this.handleWebSocketClose()
      })

      this.websocket.onMessage((res) => {
        this.handleWebSocketMessage(res)
      })
    },

    // 处理 WebSocket 消息
    handleWebSocketMessage(res) {
      const message = JSON.parse(res.data)
      console.log('onMessage', message)
      if (message.type === 'pong') {
        return
      }
      if (message.type === 'login') {
        this.userInfo = message.user
        return
      }
      if (message.type === 'error') {
        uni.showToast({
          title: message.msg,
          icon: 'none'
        })
        return
      }
      this.messages.push({
        ...message,
        isSelf: false,
        avatar: this.targetUser.avatar,
        status: 'success'
      })
      this.$nextTick(() => {
        this.scrollToBottom()
      })
    },

    // 处理 WebSocket 关闭
    handleWebSocketClose() {
      if (this.leave) {
        console.log('页面已离开，不再重连');
        return;
      }
      if (this.reconnectTimes < this.maxReconnectTimes) {
        setTimeout(() => {
          this.reconnectTimes++
          this.connectWebSocket()
        }, 10000)
      } else {
        if (this.heartbeatInterval) { // 清除心跳检测定时器
          clearInterval(this.heartbeatInterval);
          this.heartbeatInterval = null;
        }

        /*uni.showToast({
          title: '客服暂时离线，请留言',
          icon: 'none'
        })*/
      }
    },

    // 滚动到底部
    scrollToBottom() {
      this.$nextTick(() => {
        setTimeout(() => {
          const messageHeight = 100; // 假设每条消息的高度为 100rpx，调整为实际高度
          this.scrollTop = this.messages.length * messageHeight + 300; // 计算总高度
          console.log('滚动到底部', this.scrollTop)
        }, 100); // 延迟100毫秒，确保DOM更新
      });
    },

    //发送websocket消息
    async send(message) {
      if (!this.websocket || this.websocket.readyState !== this.websocket.OPEN) {
        uni.showToast({
          title: '功能暂不可用，请留言反馈',
          icon: 'none'
        })
      }
      this.websocket.send({
        data: JSON.stringify(message),
        success: () => {
          message.status = 'success';
        },
        fail: () => {
          message.status = 'failed';
        }
      });
      this.messages.push(message);
      this.scrollToBottom(); // 发送后滚动到底部
      this.showEmojiPanel = false;
    },

    // 发送消息
    async sendMessage() {
      if (!this.inputMessage.trim()) return;
      console.log('sendMessage websocket', this.websocket)

      if (!this.websocket || this.websocket.readyState !== this.websocket.OPEN) {
        uni.showToast({
          title: '功能暂不可用，请留言反馈',
          icon: 'none'
        })
      }
      const message = {
        content: this.inputMessage,
        isSelf: true,
        type: 'text',
        avatar: this.userInfo.avatar,
        status: 'sending',
        timestamp: Date.now()
      };

      await this.send(message)


      this.inputMessage = ''; // 清空输入框
      return;
      this.messages.push(message);
      this.scrollToBottom(); // 发送后滚动到底部
      this.showEmojiPanel = false;
      // WebSocket 发送消息
      if (this.websocket) {
        this.websocket.send({
          data: JSON.stringify({
            type: 'text',
            content: message.content
          }),
          success: () => {
            message.status = 'success';
          },
          fail: () => {
            message.status = 'failed';
          }
        });
      }
    },

    // 提交留言
    async submitLeaveMessage() {
      if (!this.leaveMessage.content) {
        uni.showToast({
          title: '请填写完整信息',
          icon: 'none'
        })
        return
      }

      try {
        const res = await offline_msg(this.leaveMessage)

        uni.showToast({
          title: res.msg,
          icon: res.code === 0 ? 'success' : 'none'
        })

        // 清空留言表单
        this.leaveMessage = {
          name: '',
          phone: '',
          content: ''
        }
      } catch (error) {
        uni.showToast({
          title: '留言提交失败',
          icon: 'none'
        })
      }
    },

    // 加载更多消息
    async loadMoreMessages() {
      if (this.isLoading) return;
      this.isLoading = true;

      const res = await chat_list(Object.assign(this.options, {
        page: this.page,
        pageSize: this.pageSize
      }));

      if (res.code !== 0) {
        uni.showToast({
          title: res.msg,
          icon: 'none'
        });
        this.isLoading = false;
        return;
      }
      if (res.data.list.length === 0) {
        this.isLoading = false;
        return;
      }
      const historicalMessages = res.data.list;

      this.messages.unshift(...historicalMessages);
      if (this.page == 1) {
        this.$nextTick(() => {
          this.scrollToBottom();
        })
      }
      this.page++;
      this.isLoading = false;

    },

    // 下拉刷新
    async onRefresh() {
      this.isRefreshing = true
      await this.loadMoreMessages()
      this.isRefreshing = false
    },

    chooseFile() {
      // #ifdef MP-WEIXIN
      // 微信小程序使用 chooseMessageFile
      wx.chooseMessageFile({
        count: 1,
        type: 'file',
        success: (res) => {
          const file = res.tempFiles[0]
          this.sendFileMessage({
            name: file.name,
            size: file.size,
            type: file.name.split('.').pop().toLowerCase(),
            url: file.path
          })
        }
      })
      // #endif

      // #ifdef H5

      // H5 使用 input type="file"
      const input = document.createElement('input')
      input.type = 'file'
      input.onchange = (event) => {
        const file = event.target.files[0]
        if (file) {
          this.sendFileMessage({
            name: file.name,
            size: file.size,
            type: file.name.split('.').pop().toLowerCase(),
            url: URL.createObjectURL(file)
          })
        }
      }
      input.click()
      // #endif

      // #ifdef APP-PLUS
      // 使用 plus.io 打开文件选择器

      let that = this;


      // 使用立即执行函数表达式（IIFE）来封装文件选择逻辑
      (function chooseAndProcessFile() {
        plus.gallery.pick(function (path) {
          // 成功选择了文件
          console.log('选择文件路径：', path);
          processSelectedFile(path);
        }, function (e) {
          // 选择文件失败
          if (e.code !== 12) { // 用户取消选择时不提示错误
            uni.showToast({
              title: '文件选择失败，请重试',
              icon: 'none'
            });
          }
        }, {
          filter: "none", // 允许选择所有类型的文件
          multiple: false,
          maximum: 1,
          system: false,
          preview: false,
          permissionAlert: true, // 如果没有权限时显示提示
        });

        // 处理选择的文件
        function processSelectedFile(filePath) {
          plus.io.resolveLocalFileSystemURL(filePath, function (entry) {
            entry.file(function (file) {
              that.sendFileMessage({
                name: file.name,
                size: file.size,
                type: file.name.split('.').pop().toLowerCase(),
                url: filePath // 或者使用file.localURL取决于你的需求和实际测试效果
              });
            }, function (e) {
              console.error('读取文件失败：', e.message);
              uni.showToast({
                title: '文件读取失败，请重试',
                icon: 'none'
              });
            });
          }, function (e) {
            console.error('解析本地文件路径失败：', e.message);
            uni.showToast({
              title: '无法解析文件路径，请重试',
              icon: 'none'
            });
          });
        }
      })(); // 立即执行


      // #endif
    },


    // 发送文件消息
    sendFileMessage(fileInfo) {
      const message = {
        type: 'file',
        content: fileInfo.url,
        file_info: fileInfo,
        isSelf: true,
        avatar: this.userInfo.avatar,
        status: 'sending',
        timestamp: Date.now()
      }

      //this.messages.push(message)
      //  this.scrollToBottom()

      //文件上传到服务器的逻辑
      fileInfo.path = fileInfo.url;

      console.log('fileInfo', fileInfo)

      this.uploadFile(fileInfo, 'file', (res => {
        if (res.code == 0) {
          message.status = 'success'
          message.content = res.data.full_url
          this.send(message)
          return;
          this.websocket.send({
            data: JSON.stringify({
              type: 'file',
              content: res.data.full_url
            }),
            success: () => {
              message.file_info.size = res.data.size
              message.status = 'success';
            },
            fail: () => {
              message.status = 'failed';
            }
          });
        } else {
          message.status = 'failed'
          uni.showToast({
            title: res.msg,
            icon: 'none'
          })
        }
      }))
    }
    ,

    getFileIcon(ext) {
      return this.fileIcons[ext] || this.fileIcons.default
    }
    ,

    formatFileSize(bytes) {
      if (bytes < 1024) return bytes + 'B'
      if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + 'KB'
      return (bytes / (1024 * 1024)).toFixed(1) + 'MB'
    }
    ,

    downloadFile(msg) {
      let fileInfo = msg.file_info;
      uni.downloadFile({
        url: fileInfo.url,
        success: (res) => {
          if (res.statusCode === 200) {
            uni.openDocument({
              filePath: res.tempFilePath,
              success: () => {
                console.log('文件打开成功')
              }
            })
          }
        }
      })
    }
    ,

    previewImage(url) {
      uni.previewImage({
        urls: [url],
        current: url
      })
    }
    ,

    toggleEmojiPanel() {
      this.showEmojiPanel = !this.showEmojiPanel
      if (this.showEmojiPanel) {
        this.$nextTick(() => {
          this.scrollToBottom()
        })
      }
    }
    ,

    //todo 检测是否授权了权限
    chooseImage() {
      uni.chooseImage({
        count: 9,
        sizeType: ['original', 'compressed'],
        sourceType: ['album', 'camera'],
        success: (res) => {
          const tempFilePaths = res.tempFilePaths
          tempFilePaths.forEach(path => {
            this.sendImageMessage(path)
          })
        }
      })
    }
    ,

    // 发送上传文件
    uploadFile(fileInfo, type, callback) {
      this.options.to_table = 'chat_messages';
      uni.showLoading({
        title: '处理中...',
        mask: true,
      })
      uni.uploadFile({
        url: type === 'image' ? this.uploadImageUrl : this.uploadFileUrl,
        name: 'file',//文件对应的 key , 开发者在服务器端通过这个 key 可以获取到文件二进制内容
        timeout: 60000,//超时时间ms
        formData: Object.assign(this.options, fileInfo),
        //files:[],
        fileType: this.limitType,
        filePath: fileInfo.path,//是（files和filePath选其一）
        header: {
          'Appid': constConfig.app_id,
          'Authorization': 'Bearer ' + (uni.getStorageSync('UserToken') || ''),
          'platform': uni.getSystemInfoSync().platform || '',
          'version': uni.getSystemInfoSync().version || '',
          'appVersion': uni.getSystemInfoSync().appVersion || '',
          'appVersionCode': uni.getSystemInfoSync().appVersionCode || '',
          'uniRuntimeVersion': uni.getSystemInfoSync().uniRuntimeVersion || '',
          'appWgtVersion': uni.getSystemInfoSync().appWgtVersion || '',
          // #ifdef APP-PLUS
          'bsfrom': 'app',
          // #endif
          // #ifdef H5
          'bsfrom': 'h5',
          // #endif
          // #ifdef MP-WEIXIN
          'bsfrom': 'xcx',
          // #endif
        },

        success: ({data}) => {
          console.log('yyydata', data)
          const res = JSON.parse(data)
          console.log('上传结果', res)
          callback(res)
        },
        fail: (uploadRes) => {
          callback({
            code: 500,
            msg: '上传失败，请重试'
          })
        },
        complete: (uploadRes) => {
          uni.hideLoading()
        },
      })
    }
    ,

    sendImageMessage(path) {
      const message = {
        type: 'image',
        content: path,
        isSelf: true,
        avatar: '/static/user-avatar.png',
        status: 'sending',
        timestamp: Date.now()
      }

      let that = this;


      this.uploadFile({path: path}, 'image', function (res) {
        console.log('uplaodF', res)
        if (res.code !== 0) {
          message.status = 'failed'
        } else {
          console.log('上传成功', res.data)
          message.status = 'success'
          message.content = res.data.full_url
          that.send(message)
          /*that.websocket.send({
            data: JSON.stringify({
              type: 'image',
              content: res.data.full_url,
              timestamp: Date.now()
            })
          })*/
        }
      })

      // that.messages.push(message)
      // that.scrollToBottom()

      //  console.log('sendImageMessage', path)

    }
    ,

    selectEmoji(emoji) {
      this.inputMessage += emoji
    },

    calculateScrollViewHeight() {
      const systemInfo = uni.getSystemInfoSync();
      const inputAreaHeight = 180; // 输入面板的高度
      this.scrollViewHeight = systemInfo.windowHeight - inputAreaHeight; // 计算 scroll-view 的高度
    }
    ,
  }
}
</script>

<style lang="scss" scoped>
@import 'chat.scss';
</style>
